import { TYPES } from './util'
import getModeImage from './images'
import { getImageInfo } from './images'
import Methods from './methods'
import QRCodeAlg from './qrcode'
export default class Draw extends Methods {
	constructor() {
		super()
	}

	/**
	 * 绘制矩形
	 * @param { Object } params 绘制内容
	 * @param { Object } conversion 是否转换单位默认true
	 */
	drawRect(params = {}, conversion) {
		const { canvasWidth, Context, unit } = this
		let { x, y, w, h, r, color, alpha, isFill, lineWidth, 
			windowAlign, rotate, drawImage, 
			borderColor, borderWidth, borderType, shadow, gradient, offsetRight
		} = this.getDrawParams(params, 'rect', conversion)
		if (color === 'black') color = '#ffffff'
		if (typeof r === 'number') {
			if (r * 2 > h) {
				r = h / 2
			}
		}
		if (!drawImage && rotate.deg) {
			Context.save()
			this.setRotate(x, y, w, h, rotate)
		}
		if (drawImage && shadow.show) {
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		if (!drawImage && shadow.show) {
			// Context.save()
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		if (windowAlign != 'none') {
			x = this.computedCenterX(canvasWidth, w, windowAlign, offsetRight) || x
		}
		let tr = 0
		let tl = 0
		let br = 0
		let bl = 0
		if (typeof borderType == 'string') {
			switch(borderType) {
				case 'tr':
					tr = r
					break
				case 'tl':
					tl = r
					break
				case 'br':
					br = r
					break
				case 'bl':
					bl = r
					break
				default:
					tr = r
					tl = r
					br = r
					bl = r
			}
		}
		// console.log('borderType', borderType)
		if (borderType instanceof Array && typeof r === 'number') {
			if (borderType.includes('tr')) {
				tr = r
			}
			if (borderType.includes('tl')) {
				tl = r
			}
			if (borderType.includes('br')) {
				br = r
			}
			if (borderType.includes('bl')) {
				bl = r
			}
			if (borderType.includes('default')) {
				tr = r
				tl = r
				br = r
				bl = r
			}
		}
		if (typeof r === 'object') {
			const length = r.length
			if (length === 1) {
				tl = r[0]
				tr = r[0]
				br = r[0]
				bl = r[0]
			}
			if (length === 2) {
				tl = r[0]
				tr = r[1]
				br = r[0]
				bl = r[1]
			}
			if (length === 3) {
				tl = r[0]
				tr = r[1]
				br = r[2]
				bl = r[1]
			}
			if (length === 4) {
				tl = r[0]
				tr = r[1]
				br = r[2]
				bl = r[3]
			}
		}
		// 上右 tr
		Context.lineTo(x + tl, y)
		Context.arc(x + w - tr, y + tr, tr, Math.PI * 1.5, 0, false)
		// 下右 br
		Context.lineTo(x + w, y + h - br)
		Context.arc(x + w - br,y + h - br, br, 0, Math.PI * .5, false)
		// 下左 bl
		Context.lineTo(x + bl, y + h)
		Context.arc(x + bl, y + h - bl, bl, Math.PI * .5, Math.PI, false)
		// 上左 tl
		Context.lineTo(x, y + tl)
		Context.arc(x + tl, y + tl, tl, Math.PI * 1, Math.PI * 1.5, false)
		Context.closePath()
		if (isFill) {
			if (borderWidth != 0) {
				// console.log(borderWidth)
				// console.log(borderColor)
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			if (gradient.show) {
				const { type = 'linear', relative, position, colors } = gradient
				color = this.getGradient(type, relative, this.conversionUnit(position), colors, { x, y })
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (!drawImage && rotate.deg) {
			Context.restore()
		}
		// if (!drawImage && shadow.show) {
		// 	// Context.restore()
		// }
		return Promise.resolve(true)
	}
	
	/**
	 * 绘制圆
	 * @param { Object } params 绘制内容
	 * @param { Object } conversion 是否转换单位默认true
	 */
	drawArc(params = {}, conversion = true) {
		const { canvasWidth, Context } = this
		let { x, y, r, s, e, d, alpha, isFill, lineWidth, color, rotate,
			windowAlign, borderColor, borderWidth, offsetRight,
			drawImage, shadow, gradient } = this.getDrawParams(params, 'arc', conversion)
		if (shadow.show) {
			// Context.save()
			Context.setShadow(shadow.x, shadow.y, shadow.blur, shadow.color)
		}
		x = x + r
		y = y + r
		if (windowAlign != 'none') {
			x = this.computedCenterX(canvasWidth, r * 2, windowAlign, offsetRight)
			x += r
		}
		if (!drawImage && rotate.deg) {
			Context.save()
			this.setRotate(x - r, y - r, r * 2, r * 2, rotate)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		Context.arc(x, y, r, s, e, d)
		if (isFill) {
			if (borderWidth != 0) {
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			if (gradient.show) {
				const { type, relative, position, colors } = gradient
				color = this.getGradient(type || 'linear', relative, this.conversionUnit(position), colors, { x, y })
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (!drawImage && shadow.show) {
			// console.log('进入')
			// Context.restore()
		}
		if (!drawImage && rotate.deg) {
			Context.restore()
		}
	}

	/**
	 * 绘制三角形
	 * @param { Object } params 绘制内容
	 * @param { Object } conversion 是否转换单位默认true
	 */
	drawTriangle(params = {}, conversion) {
		const { Context, canvasWidth } = this
		let { x, y, w, h, color, alpha, isFill, lineWidth, drawType, offsetRight,
			coordinate, rotate, windowAlign, direction, borderWidth, borderColor 
		} = this.getDrawParams(params, 'triangle', conversion)
		if (windowAlign != 'none' && drawType != 'custom') {
			x = this.computedCenterX(canvasWidth, w, windowAlign, offsetRight)
		}
		if (rotate.deg && drawType != 'custom') {
			Context.save()
			this.setTriangleRotate(x, y, w, h, rotate, drawType)
		}
		Context.beginPath()
		this.setAlpha(alpha)
		if (drawType == 'isosceles') {
			switch (direction) {
				case 'top':
					Context.lineTo(x + w / 2, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					break
				case 'bottom':
					Context.lineTo(x, y)
					Context.lineTo(x + w, y)
					Context.lineTo(x + w / 2, y + h)
					break
				case 'right':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h / 2)
					break
				case 'left':
					Context.lineTo(x + w, y)
					Context.lineTo(x + w, y + h)
					Context.lineTo(x, y + h / 2)
					break
			}
		} else if (drawType == 'right') {
			switch (direction) {
				case 'top':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					break
				case 'bottom':
					Context.lineTo(x, y)
					Context.lineTo(x + w, y)
					Context.lineTo(x, y + h)
					break
				case 'left':
					Context.lineTo(x, y)
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y)
					break
				case 'right':
					Context.lineTo(x, y + h)
					Context.lineTo(x + w, y + h)
					Context.lineTo(x + w, y)
					break
			}
			
		} else if (drawType == 'custom') {
			for (let i of coordinate) {
				Context.lineTo(i[0], i[1])
			}
		}
		Context.closePath()
		if (isFill) {
			if (borderWidth != 0) {
				this.setLineWidth(borderWidth)
				this.setStrokeStyle(borderColor)
				Context.stroke()
			}
			this.setFillStyle(color)
			Context.fill()
		} else {
			this.setLineWidth(lineWidth)
			this.setStrokeStyle(color)
			Context.stroke()
		}
		this.setAlpha(1)
		if (rotate.deg && drawType != 'custom') {
			Context.restore()
		}
	}

	/**
	 * 画线
	 * @param { Object } params 绘制内容 
	 * @param { Object } conversion 是否转换单位默认true
	 */
	drawLine(params = {}, conversion = true) {
		const { canvasWidth, Context, type } = this
		let { 
			x, y, color, w, algin, alpha, lineType, pattern, 
			offset, lineCap, lineWidth, windowAlign, offsetRight
		} = this.getDrawParams(params, 'line', conversion)
		Context.beginPath()
		this.setAlpha(alpha)
		if (lineType == 'dashed') {
			if (!TYPES.includes(this.type)) {
				Context.setLineDash(pattern, offset)
			} else {
				Context.setLineDash(pattern)
				Context.lineDashOffset = offset
			}
		}
		if (!TYPES.includes(type)) {
			Context.setLineCap(lineCap)
		} else {
			Context.lineCap = lineCap
		}
		this.setLineWidth(lineWidth)
		this.setStrokeStyle(color)
		switch (algin) {
			case 'right':
				if (windowAlign != 'none') {
					x = this.computedCenterX(canvasWidth, w, windowAlign, offsetRight)
				}
				Context.moveTo(x, y)
				Context.lineTo(w + x, y)
				break
			case 'left':
				if (windowAlign != 'none') {
					x = this.computedCenterX(canvasWidth, w, windowAlign, offsetRight)
				}
				Context.moveTo(x, y)
				Context.lineTo(windowAlign == 'none' ? x - w : x + w, y)
				break
			case 'top':
				Context.moveTo(x, y)
				Context.lineTo(x, -(y + w))
				break
			case 'bottom':
				Context.moveTo(x, y)
				Context.lineTo(x, y + w)
				break
		}
		Context.stroke()
		Context.closePath()
		if (!TYPES.includes(type)) {
			Context.setLineDash()
		} else {
			Context.setLineDash([0, 0])
			Context.lineDashOffset = 0
		}
		this.setAlpha(1)
	}

	/**
	 * 绘制图片
	 * @param { Object } params 绘制内容
	 * @param { Object } conversion 是否转换单位默认true
	 */
	drawImage(params = {}, conversion = true) {
		const { canvasWidth } = this
		return new Promise(async resolve => {
			try {
				let { x, y, w, h, r, src, alpha, drawType, borderWidth, windowAlign, color, mode, rotate, 
					triangle, isCompressImage, quality, borderColor, borderType, shadow,
					drawSrc, drawModeImage, drawImageInfo, offsetRight } = this.getDrawParams(params, 'image', conversion)
				if (!/\S/.test(src)) {
					return resolve({
						success: false,
						message: '图片路径为空'
					})
				}
				if (!TYPES.includes(this.type)) {
					// 不是2d需要先下载本地
					let srcRes = await this.getImageSrc(src)
					if (!srcRes.success) {
						return srcRes
					}
					src = srcRes.src
				}
				if (windowAlign != 'none') {
					x = this.computedCenterX(canvasWidth, w, windowAlign, offsetRight)
				}
				// #ifndef H5
				// 压缩图片(不支持H5)
				// if (isCompressImage) {
				// 	let compressRes = await compressImage({
				// 		src,
				// 		quality
				// 	})
				// 	if (!compressRes.success) {
				// 		return resolve(compressRes)
				// 	}
				// 	src = compressRes.src
				// }
				// #endif
				// showLoading('获取图片信息中....')
				// console.log('src', src)
				let imageInfo = drawModeImage
				if (!imageInfo) {
					imageInfo = await getImageInfo(src)
					if (!imageInfo.success) {
						uni.hideLoading()
						return resolve(imageInfo)
					}
				}
				const img = this.getImage(src)
				if (TYPES.includes(this.type)) {
					img.onload = async () => {
						return resolve(await this.drawImageByType({
							imageInfo, r, x, y, w, h, rotate,
							borderWidth, borderColor, color, alpha, borderType, triangle, 
							mode, drawType, img, shadow, drawSrc, drawModeImage
						}))
					}
				} else {
					return resolve(await this.drawImageByType({
						imageInfo, r, x, y, w, h, rotate,
						borderWidth, borderColor, color, alpha, borderType, triangle, 
						mode, drawType, img, shadow, drawSrc, drawModeImage
					}))
				}
			} catch(e) {
				return resolve({
					success: false,
					msg: '绘制图片出错' + e
				})
			}
		})
	}

	/**
	 * 据类型绘制图片
	 * @param {*} params 
	 * @returns 
	 */
	drawImageByType(params) {
		let { 
			imageInfo, r, x, y, w, h, rotate,
			borderWidth, borderColor, color, alpha, borderType, triangle, 
			mode, drawType, img, shadow, drawSrc, drawModeImage
		} = params
		const { Context } = this
		return new Promise(async resolve => {
			if (h == 0) {
				h = w
			}
			let modeImage = drawModeImage
			if (!modeImage) {
				modeImage = getModeImage(Number(imageInfo.width), Number(imageInfo.height), x, y, w, h, mode)
				// this.conversionUnit(await getImageInfo(src))
			}
			const { dx, dy, dw, dh, sw, sh, sx, sy } = modeImage
			Context.save()
			Context.beginPath()
			if (drawType == 'default') {
				this.setRotate(x, y, w, h, rotate)
				// this.drawRect({
				// 	x,
				// 	y,
				// 	w,
				// 	h,
				// 	alpha,
				// 	color,
				// 	drawImage: true
				// })
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh, x, y, w, h)
				Context.clip()
				Context.restore()
			} else if (drawType == 'arc') {
				// 绘制圆形图片
				this.setRotate(x, y, w, h, rotate)
				this.drawArc({
					x,
					y,
					r: w / 2,
					borderWidth,
					borderColor,
					color,
					drawImage: true,
					shadow
				}, false)
				Context.clip()
				this.setAlpha(alpha)
				// console.log({
				// 	mode, img, dx, dy, dw, dh, sx, sy, sw, sh
				// })
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			} else if (drawType == 'rect') {
				// 绘制矩形图片
				this.setRotate(x, y, w, h, rotate)
				if (mode == 'widthFix') {
					h = sh
				}
				if (mode == 'heightFix') {
					w = sw
				}
				this.drawRect({
					x,
					y,
					w,
					h,
					alpha,
					borderWidth,
					borderColor,
					borderType,
					r,
					color,
					drawImage: true,
					shadow
				}, false)
				// console.log({
				// 	dx, dy, dw, dh, sx, sy, sw, sh
				// })
				Context.clip()
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			} else if (drawType == 'triangle') {
				// 绘制三角形图片
				let type = triangle.type || 'isosceles'
				let coordinate = triangle.coordinate || []
				let direction = triangle.direction || 'top'
				if (type != 'custom') {
					this.setTriangleRotate(x, y, w, h, rotate, type)
				}
				this.drawTriangle({
					x,
					y,
					w,
					h,
					alpha,
					borderWidth,
					borderColor,
					color,
					coordinate,
					direction,
					drawType: type
				}, false)
				Context.clip()
				this.setAlpha(alpha)
				await this.drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh)
				Context.restore()
			}
			this.setAlpha(1)
			return resolve({
				success: true,
				data: img
			})
		})
	}

	/**
	 * 绘制图片内容
	 * @returns 
	 */
	drawImageContent(mode, drawType, img, dx, dy, dw, dh, sx, sy, sw, sh, x, y, w, h) {
		const { Context } = this
		return new Promise(async resolve => {
			if (drawType == 'default') {
				await Context.drawImage(img, x, y, w, h)
			} else if (mode != 'default') {
				await Context.drawImage(img, dx, dy, dw, dh, sx, sy, sw, sh)
			} else {
				await Context.drawImage(img, dx, dy, dw, dh)
			}
			resolve(true)
		})
	}

	/**
	 * 绘制文字
	 * @param { Object } params 绘制内容 
	 */
	async drawText(params = {}) {
		const { canvasWidth, Context, company } = this
		let { x, y, w, h, text, textIndent,
			lastWidth, font, color, alpha, 
			isFill, line, windowAlign, textAlign, baseline, highlightText, textRect, offsetRight
		} = this.getDrawParams(params, 'text')
		// console.log('font', font)
		// console.log(this.getDrawParams(params, 'text'))
		Context.save()
		Context.beginPath()
		this.setAlpha(alpha)
		// console.log(`${text}----${font.style}`)
		Context.font = font.style
		// #ifdef MP-TOUTIAO
		// 不知道为啥现在字节跳动一定用这个方法来设置文字大小了. 之前还不用...
		Context.setFontSize(font.fontSize)
		// #endif
		if (!TYPES.includes(this.type)) {
			Context.setTextBaseline(baseline)
		}else{
			Context.textBaseline = baseline
		}
		if (typeof text != 'string') {
			text += ''
		}
		let textArr = params.textArr
		if (!textArr) {
			textArr = this.computedFontTextLineHeight(x, y, w, text, textIndent, lastWidth, font, line, textAlign, windowAlign, color, offsetRight)
		}
		if (highlightText.length != 0) {
			textArr = this.getHighlightText(textArr, highlightText, color, font)
		}
		// console.log('textArr', textArr)
		if (textRect.show) {
			// 水平的 垂直的
			const { vorizontal, vertical, ...textReactParmas } = this.conversionUnit(textRect)
			// console.log({
			// 	vorizontal,
			// 	vertical,
			// })
			let tw = w == canvasWidth ? this.conversionUnit(params).tw || canvasWidth : w
			const firstText = textArr[0]
			let tx = firstText.x - vorizontal
			let ty = firstText.y - vertical
			let ey = textArr[textArr.length - 1].y + font.fontSize
			let th = ey - firstText.y
			th += vertical * 2
			// #ifdef MP-WEIXIN || MP-TOUTIAO
			if (uni.getSystemInfoSync().platform === 'android') {
				ty += font.fontSize / 3
				th -= font.fontSize / 3
			}
			// #endif
			tw += (vorizontal * 2)
			await this.drawRect({
				x: tx,
				y: ty,
				w: tw,
				h: th,
				...textReactParmas
			}, false)
		}
		if (isFill) {
			Context.font = font.style
			for (let i of textArr) {
				let { text, x, y, tx, ty, tw, fontColor } = i
				this.setFillStyle(fontColor)
				Context.fillText(text, x, y)
				if (line.lineStyle != 'none') {
					this.setFillStyle(color)
					this.drawLine({
						x: tx,
						y: ty,
						w: tw,
						color,
						lineType: line.lineType,
						lineWidth: line.lineWidth
					}, false)
				}
			}
		} else {
			for (let i of textArr) {
				let { text, x, y, tx, ty, tw, fontColor } = i
				this.setStrokeStyle(fontColor)
				Context.strokeText(text, x, y)
				if (line.lineStyle != 'none') {
					this.setStrokeStyle(color)
					this.drawLine({
						x: tx,
						y: ty,
						w: tw,
						color,
						lineType: line.lineType,
						lineWidth: line.lineWidth
					}, false)
				}
			}
		}
		Context.restore()
		Context.font = this.getFont().style
		this.setAlpha(1)
	}

	/**
	 * 绘制二维码
	 * @param { Object } params 二维码参数
	 */
	drawQrCode(params = {}) {
		const { Context, canvasWidth } = this
		return new Promise(async resolve => {
			let { x, y, image, windowAlign, offsetRight, ...options } = this.getDrawParams(params, 'qrcode')
			if (windowAlign != 'none') {
				x = this.computedCenterX(canvasWidth, options.size, windowAlign, offsetRight)
			}
			//使用QRCodeAlg创建二维码结构
			let qrcodeAlgObjCache = []
			let qrCodeAlg = null
			let l = qrcodeAlgObjCache.length
			let d = 0
			for (let i = 0;i < l; i++) {
				d = i
				if (qrcodeAlgObjCache[i].text == options.text && qrcodeAlgObjCache[i].text.correctLevel == options.correctLevel) {
					qrCodeAlg = qrcodeAlgObjCache[i].obj
					break
				}
			}
			if (d == l) {
				qrCodeAlg = new QRCodeAlg(options.text, options.correctLevel)
				qrcodeAlgObjCache.push({
					text: options.text,
					correctLevel: options.correctLevel,
					obj: qrCodeAlg
				})
			}
			/**
			 * 计算矩阵点的前景色
			 * @param {Obj} config
			 * @param {Number} config.row 点x坐标
			 * @param {Number} config.col 点y坐标
			 * @param {Number} config.count 矩阵大小
			 * @param {Number} config.options 组件的options
			 * @return {String}
			 */
			let getForeGround = function (config) {
				let options = config.options
				if (options.pdground && (
					(config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
					(config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
					(config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
				)) {
					return options.pdground
				}
				return options.foreground
			}
			let count = qrCodeAlg.getModuleCount()
			let ratioSize = options.size
			let ratioImgSize = this.getUnit(image.size) || 30
			//计算每个点的长宽
			let tileW = (ratioSize / count).toPrecision(4)
			let tileH = (ratioSize / count).toPrecision(4)
			//绘制
			for (let row = 0; row < count; row++) {
				for (let col = 0; col < count; col++) {
					let w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW))
					let h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW))
					let foreground = getForeGround({
						row: row,
						col: col,
						count: count,
						options: options
					})
					this.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background)
					Context.fillRect(x + Math.round(col * tileW), y + Math.round(row * tileH), w, h)
				}
			}
			if (image.src) {
				const { src, r, color, borderWidth, borderColor } = image
				const dx = x + Number(((ratioSize - ratioImgSize) / 2).toFixed(2))
				const dy = y + Number(((ratioSize - ratioImgSize) / 2).toFixed(2))
				const drawImage = await this.drawImage({
					x: dx,
					y: dy,
					w: ratioImgSize,
					h: ratioImgSize,
					src,
					r,
					color,
					borderWidth,
					borderColor,
					drawType: 'rect',
					isCompressImage: false,
				}, false)
				if (!drawImage.success) {
					return resolve(drawImage)
				}
			}
			return resolve({
				success: true
			})
		})
	}
}